#pragma once

#include <memory>
#include <iostream>
#include <unordered_map>
#include "Epoller.hpp"
#include "Connection.hpp"
#include "Log.hpp"

// ET模式
class Reactor
{
    static const int revs_num = 128;

public:
    bool IsConnectionExistsHelper(int sockfd)
    {
        auto iter = _connections.find(sockfd);
        if (iter == _connections.end())
            return false;
        else
            return true;
    }
    bool IsConnectionExists(const std::shared_ptr<Connection> &conn)
    {
        return IsConnectionExistsHelper(conn->GetFd());
    }
    bool IsConnectionExists(int sockfd)
    {
        return IsConnectionExistsHelper(sockfd);
    }
    bool IsConnectionEmpty()
    {
        return _connections.empty();
    }
    int LoopOnce(int timeout)
    {
        return _epoller_ptr->Wait(_revs, revs_num, timeout);
    }
    void Dispatcher(int initial_value)
    {
        int timeout = 100;
        int n = _epoller_ptr->Wait(_revs, revs_num, timeout);
        for (int i = 0; i < initial_value; i++)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;

            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT);

            if (revents & EPOLLIN)
            {
                // 读事件就绪
                if (IsConnectionExists(sockfd))
                    _connections[sockfd]->Recver();
            }
            if (revents & EPOLLHUP)
            {
                // 写事件就绪
                if (IsConnectionExists(sockfd))
                    _connections[sockfd]->Sender();
            }
        }
    }

public:
    Reactor() : _epoller_ptr(std::make_unique<Epoller>()), _isrunning(false)
    {
    }
    void Loop()
    {
        if (IsConnectionEmpty())
            return;

        _isrunning = true;
        while (true)
        {
            int timeout = 1000;
            int n = LoopOnce(timeout);
            Dispatcher(n);
        }
        _isrunning = false;
    }
    void AddConection(std::shared_ptr<Connection> &conn)
    {
        if (IsConnectionEmpty())
        {
            LOG(LogLevel::WARNING) << "conn is exists" << conn->GetFd();
            return;
        }
        uint32_t events = conn->GetEvent();
        int sockfd = conn->GetFd();
        // 将conn对应的fd及关心的时间写透至内核
        _epoller_ptr->AddEvent(sockfd, events);

        // 设置conn的拥有者回指指针
        conn->SetOwner(this);

        // 将具体的connection添加到_connections
        _connections[sockfd] = conn;
    }
    void EnableReadWrite(int fd, bool enableread, bool enablewrite)
    {
        if (!IsConnectionExists(fd))
        {
            LOG(LogLevel::WARNING) << "enablewrite,coon is exists: " << fd;
            return;
        }

        uint32_t new_event = (EPOLLET | (enableread ? EPOLLIN : 0) | (enablewrite ? EPOLLOUT : 0))
                                 _epoller_ptr->ModEvent(sockfd, new_event);
    }
    void DelConnection(int sockfd)
    {
        _epoller_ptr->DelEvent(sockfd);
        _connections.erase(sockfd);
        close(sockfd);

        LOG(LogLevel::INFO) << "client quit";
    }
    void PrintConnection()
    {
        for(auto &conn:_connections)
        {
            std::cout << conn.second->GetFd() << " ";
        }
    }
    ~Reactor()
    {
    }

private:
    // 1. epoll模型
    std::unique_ptr<Epoller> _epoller_ptr;

    // 3. 管理所有的Connection,本质是管理所有的fd进行映射
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;
    bool _isrunning;

    struct epoll_event _revs[revs_num];
};